package com.jomoo.css.common.core.support;

import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.lang.Nullable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * bo.wang 分页对象
 */
public class DaoPage<T> implements Pageable {

	@JsonIgnore
	private final Sort sort;

	/**
	 * 记录总数
	 **/
	private long recordCount = 0;
//    private int total;
//    private int size;

	/**
	 * 当前页页数
	 **/
	private int pageIndex = 0;
//    private int number;
//    private int startPage;
//    private int page;

	/**
	 * 每页记录数
	 **/
	private int pageSize = 10;
//    private int totalPages;

	/**
	 * 当前页数据集
	 **/
	private Collection<T> result = new ArrayList<T>();

	//    private Collection<?> rows = new ArrayList<Object>();
//    private Collection<?> content = new ArrayList<Object>();
	public DaoPage(Collection content) {
		super();
		this.recordCount = null == content ? 0 : content.size();
		this.pageIndex = 0;
		this.pageSize = null == content ? 0 : content.size();
		this.result = content;
		this.sort = Sort.unsorted();
	}

	public DaoPage() {
		this(0, 0);
	}

	/**
	 * 构造函数
	 *
	 * @param recordCount 总记录数
	 * @param pageIndex   当前页数
	 * @param pageSize    每页记录数
	 * @param result      当前页数据集
	 */
	@Deprecated
	public DaoPage(long recordCount, int pageIndex, int pageSize, List<T> result) {
		super();
		this.recordCount = recordCount;
		this.pageIndex = pageIndex;
		this.pageSize = pageSize;
		this.result = result;
		this.sort = Sort.unsorted();
	}

	/**
	 * Creates a new {@link DaoPage}. Pages are zero indexed, thus providing 0 for {@code page} will return the first
	 * page.
	 *
	 * @param page zero-based page index.
	 * @param size the size of the page to be returned.
	 * @deprecated use {@link #of(int, int)} instead.
	 */
	@Deprecated
	public DaoPage(int page, int size) {
		this(page, size, Sort.unsorted());
	}

	/**
	 * Creates a new {@link DaoPage} with sort parameters applied.
	 *
	 * @param page       zero-based page index.
	 * @param size       the size of the page to be returned.
	 * @param direction  the direction of the {@link Sort} to be specified, can be {@literal null}.
	 * @param properties the properties to sort by, must not be {@literal null} or empty.
	 * @deprecated use {@link #of(int, int, Sort.Direction, String...)} instead.
	 */
	@Deprecated
	public DaoPage(int page, int size, Sort.Direction direction, String... properties) {
		this(page, size, Sort.by(direction, properties));
	}

	/**
	 * Creates a new {@link DaoPage} with sort parameters applied.
	 *
	 * @param page zero-based page index.
	 * @param size the size of the page to be returned.
	 * @param sort can be {@literal null}.
	 * @deprecated since 2.0, use {@link #of(int, int, Sort)} instead.
	 */
	@Deprecated
	public DaoPage(int page, int size, Sort sort) {

		if (page < 0) {
//            throw new IllegalArgumentException("Page index must not be less than zero!");
			page = pageIndex;
		}

		if (size < 1) {
//            throw new IllegalArgumentException("Page size must not be less than one!");
			size = pageSize;
		}

		this.pageIndex = page;
		this.pageSize = size;

		this.sort = sort;
	}

	/**
	 * Creates a new unsorted {@link DaoPage}.
	 *
	 * @param page zero-based page index.
	 * @param size the size of the page to be returned.
	 * @since 2.0
	 */
	public static DaoPage of(int page, int size) {
		return of(page, size, Sort.unsorted());
	}

	/**
	 * Creates a new {@link DaoPage} with sort parameters applied.
	 *
	 * @param page zero-based page index.
	 * @param size the size of the page to be returned.
	 * @param sort must not be {@literal null}.
	 * @since 2.0
	 */
	public static DaoPage of(int page, int size, Sort sort) {
		return new DaoPage(page, size, sort);
	}

	/**
	 * Creates a new {@link DaoPage} with sort direction and properties applied.
	 *
	 * @param page       zero-based page index.
	 * @param size       the size of the page to be returned.
	 * @param direction  must not be {@literal null}.
	 * @param properties must not be {@literal null}.
	 * @since 2.0
	 */
	public static DaoPage of(int page, int size, Sort.Direction direction, String... properties) {
		return of(page, size, Sort.by(direction, properties));
	}

//    public DaoPage() {
//        super();
//    }

	/**
	 * 获取总页数
	 *
	 * @return
	 */
	public long getPageCount() {
		if (pageSize == 0) return 0;
		if (recordCount % pageSize == 0)
			return recordCount / pageSize;
		else
			return recordCount / pageSize + 1;
	}

	/**
	 * 获取当前页数
	 *
	 * @return
	 */
	public int getPageIndex() {
		return pageIndex;
	}

	/**
	 * 设置当前页数
	 *
	 * @param pageIndex
	 * @author dada
	 */
	public void setPageIndex(int pageIndex) {
		this.pageIndex = pageIndex;
	}

	@Override
	public int getPageNumber() {
		return pageIndex;
	}

	/**
	 * 获取每页记录数
	 *
	 * @return
	 */
	public int getPageSize() {
		return pageSize;
	}

	/**
	 * 设置每页记录数
	 *
	 * @param pageSize
	 * @author dada
	 */
	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	/**
	 * 获取总记录数
	 *
	 * @return
	 */
	public long getRecordCount() {
		return recordCount;
	}

	/**
	 * 设置总记录数
	 *
	 * @param recordCount
	 * @author dada
	 */
	public void setRecordCount(long recordCount) {
		this.recordCount = recordCount;
	}

	public long getTotal() {
		return recordCount;
	}

	/**
	 * 当前页首条在数据库里的位置
	 *
	 * @return
	 */
	public int getRecordIndex() {
		return (pageIndex - 1) * pageSize;
	}

	/**
	 * 获取分页结果集
	 *
	 * @return
	 */
	public Collection<T> getResult() {
		return result;
	}

	/**
	 * 设置记录集
	 *
	 * @param result
	 * @author dada
	 */
	public void setResult(Collection<T> result) {
		this.result = result;
	}

	public int getStartPage() {
		return pageIndex;
	}

	public int getTotalPages() {
		return pageSize;
	}

	public long getSize() {
		return recordCount;
	}

	public long getNumber() {
		return recordCount;
	}

	public int getPage() {
		return pageIndex;
	}

//    public Collection<?> getContent() {
//        return result;
//    }

	/**************Pageable begin**************/
	@Override
	public long getOffset() {
		return (this.pageIndex < 0 ? 0 : this.pageIndex) * (long) this.pageSize;
	}

	@JsonIgnore
	@Override
	public Sort getSort() {
		return sort;
	}

	@Override
	public Pageable next() {
		return new DaoPage(this.getPageNumber() + 1, this.getPageSize(), this.getSort());
	}

	@Override
	public Pageable previousOrFirst() {
		return this.hasPrevious() ? this.previous() : this.first();
	}

	@Override
	public Pageable first() {
		return new DaoPage<T>(0, this.getPageSize(), this.getSort());
	}

	public DaoPage previous() {
		return this.getPageNumber() == 0 ? this : new DaoPage(this.getPageNumber() - 1, this.getPageSize(), this.getSort());
	}

	@Override
	public boolean hasPrevious() {
		return this.pageIndex > 0;
	}

	public boolean equals(@Nullable Object obj) {
		if (this == obj) {
			return true;
		} else if (!(obj instanceof DaoPage)) {
			return false;
		} else {
			DaoPage that = (DaoPage) obj;
			return super.equals(that) && this.sort.equals(that.sort);
		}
	}

	public int hashCode() {
		return 31 * super.hashCode() + this.sort.hashCode();
	}

	public String toString() {
		return String.format("Page request [number: %d, size %d, sort: %s]", this.getPageNumber(), this.getPageSize(), this.sort);
	}

	/**************Pageable end**************/

	public void setCurrentPage(Integer currentPage) {
		this.pageIndex = currentPage;
	}

	public void setCurrent(Integer current) {
		this.pageIndex = current;
	}
}
